
#include "random.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cmath>

#include "config.h"
using namespace std;

Random rng;

bool Random::init()
{
	if ( config.rng_.random_seed ){
		setSeed();
	} else{
		setSeed( config.rng_.seed );
	}
	return true;
}

void Random::setSeed(long s){
	//randomly choosing a seed 
	if(s==0){
	    srand((unsigned int)time(NULL));
	    seed=rand();
	}else {seed=s;}
}

/*-------------  UNIFORM [0, 1] RANDOM NUMBER GENERATOR  -------------*/
/*                                                                    */
/* This implementation is for Intel 8086/8 and 80286/386 CPUs using   */
/* C compilers with 16-bit short integers and 32-bit long integers.   */
/*                                                                    */
/*--------------------------------------------------------------------*/
double Random::ranf(void)
{
    short *p,*q,k; int Hi,Lo;
    /* generate product using double precision simulation  (comments  */
    /* refer to In's lower 16 bits as "L", its upper 16 bits as "H")  */
    p=(short *)&seed; Hi=*(p+1)*A;                 /* 16807*H->Hi */
    *(p+1)=0; Lo=seed*A;                           /* 16807*L->Lo */
    p=(short *)&Lo; Hi+=*(p+1);    /* add high-order bits of Lo to Hi */
    q=(short *)&Hi;                       /* low-order bits of Hi->LO */
    *(p+1)=*q&0X7FFF;                               /* clear sign bit */
    k=*(q+1)<<1; if (*q&0X8000) k++;         /* Hi bits 31-45->K */
    /* form Z + K [- M] (where Z=Lo): presubtract M to avoid overflow */
    Lo-=M; Lo+=k; if (Lo<0)  Lo+=M;
    seed=Lo;
    return((double)Lo*4.656612875E-10);             /* Lo x 1/(2**31-1) */
}

/*------------  UNIFORM [a, b] RANDOM VARIATE GENERATOR  -------------*/
int Random::uniform(int a,int b)
{ /* 'uniform' returns a psuedo-random integer from a uniform     */
      /* distribution with lower bound a and upper bound b.           */
      if (a>b)  cout<<"uniform Argument Error: a >b"<<endl;
      return (int)(a+floor((b-a)*ranf()));
}

/*--------------  EXPONENTIAL RANDOM VARIATE GENERATOR  --------------*/
double Random::expntl(double x)
{ /* 'expntl' returns a psuedo-random variate from a negative     */
      /* exponential distribution with mean x.                        */
      return(-x*log(ranf()));
}

/*-----------------  NORMAL RANDOM VARIATE GENERATOR  ----------------*/
double Random::normal(double x,double s)
{ /* 'normal' returns a psuedo-random variate from a normal dis-  */
      /* tribution with mean x and standard deviation s.              */
      double v1,v2,w,z1; static double z2=0.0;
      if (z2!=0.0)
        {z1=z2; z2=0.0;}  /* use value from previous call */
        else
          {
            do
              {v1=2.0*ranf()-1.0; v2=2.0*ranf()-1.0; w=v1*v1+v2*v2;}
            while (w>=1.0);
            w=sqrt((-2.0*log(w))/w); z1=v1*w; z2=v2*w;
          }
      return(x+z1*s);
}

/*-----------------  TRIANGULAR RANDOM VARIATE GENERATOR  ----------------*/
double Random::triangular(double a,double b,double c)
{ /* 'triangular' returns a psuedo-random variate from a triangular     */
      /* distribution with lower bound a and upper bound c and mode b.           */
    double r;  
	if (a>b || a>c || b>c) cout<<"triangular Argument Error: a>b>c"<<endl;
      r=ranf();
	  if(r<= (b-a)/(c-a))
		  return (a+sqrt(r*(b-a)*(c-a)));
	  else
	  return(c-sqrt((c-b)*(c-a)*(1-r)));
}

